package com.hzjq.core.receive

import android.text.TextUtils
import com.hzjq.core.BlastDelegate
import com.hzjq.core.callback.SimpleCallback
import com.hzjq.core.cmd.Cmd
import com.hzjq.core.cmd.CmdExeImpl
import com.hzjq.core.massage.DataMessageBean
import com.hzjq.core.worker.BackWork
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.*
import kotlin.collections.HashMap

class Receives {

    private val receives = HashMap<Cmd, Receiver>()

    private var willRemoveReceiver = arrayListOf<Cmd>()

    private val willAddReceiver = HashMap<Cmd, Receiver>()

    private var lock = false

    private var isInterceptor = false

    private var msgLooper = java.util.ArrayList<String>()

    private var mLooperThread: LooperThread? = null

    private var loopering = false

    private constructor() {
        EventBus.getDefault().register(this)
        makeLooperStart()
    }


    private object B {
        val b = Receives()
    }

    companion object {

        /**
         * 获取起爆入口类，单例
         */
        fun getInstance(): Receives {
            return B.b
        }
    }

    /**
     * 找到对应的接收者并执行
     */
    @Synchronized
    fun findReceiverDoWork(msg: String) {
        if (!msgLooper.contains(msg) && !msg.isNullOrBlank()) {
            msgLooper.add(msg)
            makeLooperStart()
        }
    }


    private fun makeLooperStart(){
        if (mLooperThread == null || !mLooperThread!!.isAlive() || mLooperThread!!.isInterrupted()) {
            mLooperThread = LooperThread()
            mLooperThread?.start()
        }
    }


    inner class LooperThread : Thread(){
        override fun run() {
            super.run()
            while (!isInterrupted()) {
                if (msgLooper.isNotEmpty() && !loopering) {
                    try {
                        val msg = msgLooper.get(0)
                        if (!msg.isNullOrBlank()) {
                            loopering = true
                            removeAt()
                            queue(msg)
                        }
                    } catch (e: Exception) {
                        loopering = false
                        e.printStackTrace()
                    }
                }
            }
        }
    }



    private fun removeAt() {
        try {
            if(msgLooper.isNotEmpty()) {
                msgLooper.removeAt(0)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }


    private fun queue(msg: String) {
        try {
            if (!isInterceptor) {
                checkAddAndRemoveCmd()
                receives.forEach {
                    val cmd = findReceiverCmd(msg, it.key, it.value)
                    if (cmd) {
                        BlastDelegate.getDelegate().getCmdExeLoader().cancel()
                        unRegisterReceiver(it.key)
                        return@forEach
                    }
                }
                loopering = false
            }
        } catch (e: ConcurrentModificationException) {
            e.printStackTrace()
            checkAddAndRemoveCmd()
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }


    /**
     * 检查是否有新注册的或者已被标记移除的cmd
     */
    private fun checkAddAndRemoveCmd() {
        try {
            val removes = arrayListOf<Cmd>()
            val wremoves = arrayListOf<Cmd>()
//            BlastLog.e("willRemoveReceiver:${willRemoveReceiver.size} willAddReceiver:${willAddReceiver.size}")
            if (willRemoveReceiver.isNotEmpty()) {
                val size = willRemoveReceiver.size
                for (i in 0 until size) {
                    if (i < willRemoveReceiver.size) {
                        val rc = willRemoveReceiver[i]
                        receives.forEach { rec ->
                            if (TextUtils.equals(rc.cmd, rec.key.cmd)) {
                                removes.add(rec.key)
                                wremoves.add(rc)
                            }
                        }
                    }
                }

                removes.forEach {
                    receives.remove(it)
                }
                wremoves.forEach {
                    willRemoveReceiver.remove(it)
                }
            }
            if (willAddReceiver.isNotEmpty()) {
                receives.putAll(willAddReceiver)
                willAddReceiver.clear()
            }
//            BlastLog.e("receives:${receives.size}")
        } catch (e: ConcurrentModificationException) {
            willRemoveReceiver.clear()
            e.printStackTrace()
        }
    }


    /**
     * 执行拦截器
     */
    private fun exeInterceptor(cmd: Cmd, msg: String): Boolean {
        if (cmd.checker == null) {
            return false
        } else {
            try {
                val check = cmd.checker?.check(msg)!!
                if (check != 0) {
                    if(check == 104){
                        BackWork(SimpleCallback()).backSimple()
                    }
                    val list = ReceiverInterceptorPool.getInstance().getAllInterceptor()
                    list.forEach {
                        val b = it.onInterceptor(check)
                        if (b) {
                            onInterceptorRemoveReceiver(cmd)
                            BlastDelegate.getDelegate().getCmdExeLoader().cancel()
                            return true
                        }
                    }
                }
            } catch (e: ConcurrentModificationException) {
                e.printStackTrace()
            }
        }
        return false
    }

    /**
     * 注册接收者
     */
    fun registerReceiver(cmd: Cmd, receiver: Receiver) {
        try {
            var addItem: Cmd? = null
            willAddReceiver.forEach {
                if (TextUtils.equals(it.key.cmd, cmd.cmd)) {
                    addItem = it.key
                    return@forEach
                }
            }
            if (addItem == null) {
                willAddReceiver[cmd] = receiver
            }
        } catch (e: ConcurrentModificationException) {
            checkAddAndRemoveCmd()
            e.printStackTrace()
        }
    }


    /**
     * 取消注册接收者
     */
    fun unRegisterReceiver(cmd: Cmd) {
        try {
            val size = willRemoveReceiver.size
            for (i in 0 until size) {
                if (i < willRemoveReceiver.size) {
                    val it = willRemoveReceiver[i]
                    if (TextUtils.equals(it.cmd, cmd.cmd)) {
                        return
                    }
                }
            }
            if (!willRemoveReceiver.contains(cmd)) {
                willRemoveReceiver.add(cmd)
            }
        } catch (e: ConcurrentModificationException) {
            checkAddAndRemoveCmd()
            e.printStackTrace()
        }
    }


    /**
     * 拦截后移除
     */
    fun onInterceptorRemoveReceiver(cmd: Cmd) {
        isInterceptor = true
        willAddReceiver.remove(cmd)
        receives.remove(cmd)
        isInterceptor = false
    }

    /**
     * 拦截后移除
     */
    fun onInterceptorClearReceiver() {
        isInterceptor = true
        willAddReceiver.clear()
        receives.clear()
        willRemoveReceiver.clear()
        isInterceptor = false
    }


    /**
     *  匹配cmd命令
     */
    private fun findReceiverCmd(msg: String, cmd: Cmd, receiver: Receiver): Boolean {
        if (!cmd.keyOk.isNullOrEmpty()) {
            if (msg.startsWith(cmd.keyOk)) {
                return onCallbackCmdReceiver(msg, cmd, receiver)
            }
        }
        if (!cmd.keyError.isNullOrEmpty()) {
            if (msg.startsWith(cmd.keyError)) {
                if (!exeInterceptor(cmd, msg)) {
                    val sr = CmdReceiver()
                    sr.any = null
                    sr.receiver = receiver
                    EventBus.getDefault().post(sr)
                    return true
                }
                return false
            }
        }
        return findReceiverCmdKey(msg, cmd, receiver)
    }


    /**
     * 回调
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    fun postCallback(sr: CmdReceiver) {
        BlastDelegate.getDelegate().getCmdExeLoader().cancel()
        loopering = false
        if (sr.any == null) {
            sr.receiver.failed()
        } else {
            sr.receiver.onSuccess(sr.any!!)
        }
    }

    /**
     * 匹配cmd里的key值
     */
    private fun findReceiverCmdKey(msg: String, cmd: Cmd, receiver: Receiver): Boolean {
        if (cmd.key != null) {
            if (msg.length >= cmd.key!!.endIndex) {
                if (msg.startsWith(cmd.key!!.start)) {
                    val key = msg.substring(cmd.key!!.startIndex, cmd.key!!.endIndex)
                    if (TextUtils.equals(key, cmd.key!!.key)) {
                        return onCallbackCmdReceiver(msg, cmd, receiver)
                    }
                }
            }
        }
        return false
    }


    /**
     * 回调这个指令
     */
    private fun onCallbackCmdReceiver(msg: String, cmd: Cmd, receiver: Receiver): Boolean {
        return if (retryCmdByAckLessThenMinLength(msg, cmd)) {
            lock = true
            false
        } else {
            if (!exeInterceptor(cmd, msg)) {
                val any = receiver.convert(msg)
                val sr = CmdReceiver()
                sr.any = any
                sr.receiver = receiver
                EventBus.getDefault().post(sr)
                return true
            }
            return false
        }
    }

    /**
     * 如果ack长度小于最小长度时重试
     */
    private fun retryCmdByAckLessThenMinLength(ack: String, cmd: Cmd): Boolean {
        if (cmd.minAckLength > 0 && ack.length < cmd.minAckLength) {//丢包
            val loader = BlastDelegate.getDelegate().getCmdExeLoader()
            if (loader is CmdExeImpl) {
                val msg = DataMessageBean(cmd.cmd)
                loader.retryCmdByAckLessThenMinLength(msg.assembly())
                return true
            }
        }
        return false
    }

    /**
     * 执行失败
     */
    fun onCallbackCmdFailed(cmd: ByteArray) {
        try {
            receives.forEach {
                if (cmd.contentEquals(DataMessageBean(it.key.cmd).assembly())) {
                    it.value.failed()
                    loopering = false
                    return@forEach
                }
            }
        } catch (e: ConcurrentModificationException) {
            isInterceptor = true
            receives.forEach {
                if (cmd.contentEquals(DataMessageBean(it.key.cmd).assembly())) {
                    it.value.failed()
                    loopering = false
                    return@forEach
                }
            }
            isInterceptor = false
            e.printStackTrace()
        }
    }

    class CmdReceiver {
        var any: Any? = null
        lateinit var receiver: Receiver
    }

}